home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CTOOLS10.ARJ / DLIST.C < prev    next >
C/C++ Source or Header  |  1992-02-15  |  12KB  |  391 lines

  1. /****************************************************************************
  2. *
  3. *                    Copyright (C) 1991 Kendall Bennett.
  4. *                            All rights reserved.
  5. *
  6. * Filename:        $RCSfile: dlist.c $
  7. * Version:        $Revision: 1.5 $
  8. *
  9. * Language:        ANSI C
  10. * Environment:    any
  11. *
  12. * Description:    Module to implement doubly linked lists. Includes a routine
  13. *                to peform a mergesort on the doubly linked list.
  14. *
  15. * $Id: dlist.c 1.5 91/12/31 19:39:49 kjb Exp $
  16. *
  17. * Revision History:
  18. * -----------------
  19. *
  20. * $Log:    dlist.c $
  21. * Revision 1.5  91/12/31  19:39:49  kjb
  22. * Modified include file directories.
  23. * Revision 1.4  91/10/28  03:16:39  kjb
  24. * Ported to the Iris.
  25. * Revision 1.3  91/09/27  03:09:18  kjb
  26. * Cosmetic change.
  27. * Revision 1.2  91/09/03  18:27:42  ROOT_DOS
  28. * Ported to UNIX.
  29. * Revision 1.1  91/09/01  18:35:23  ROOT_DOS
  30. * Initial revision
  31. ****************************************************************************/
  32.  
  33. #include <stdio.h>
  34. #include <malloc.h>
  35. #include <signal.h>
  36. #include "debug.h"
  37. #include "dlist.h"
  38.  
  39. PUBLIC void *dlst_newnode(int size)
  40. /****************************************************************************
  41. *
  42. * Function:        dlst_newnode
  43. * Parameters:    size    - Amount of memory to allocate for node
  44. * Returns:      Pointer to the allocated node's user space.
  45. *
  46. * Description:    Allocates the memory required for a node, adding a small
  47. *                header at the start of the node. We return a reference to
  48. *                the user space of the node, as if it had been allocated via
  49. *                malloc().
  50. *
  51. ****************************************************************************/
  52. {
  53.     DLST_BUCKET    *node;
  54.  
  55.     if ( !(node = (DLST_BUCKET*)malloc(size + sizeof(DLST_BUCKET))) ) {
  56.         fprintf(stderr,"Not enough memory to allocate list node.\n");
  57.         raise(SIGABRT);
  58.         return NULL;
  59.         }
  60.  
  61.     return DLST_USERSPACE(node);        /* Return pointer to user space */
  62. }
  63.  
  64. PUBLIC void dlst_freenode(void *node)
  65. /****************************************************************************
  66. *
  67. * Function:        dlst_freenode
  68. * Parameters:    node    - Node to free.
  69. *
  70. * Description:  Frees a node previously allocated with lst_newnode().
  71. *
  72. ****************************************************************************/
  73. {
  74.     free(DLST_HEADER(node));
  75. }
  76.  
  77. PUBLIC DLIST *dlst_init(void)
  78. /****************************************************************************
  79. *
  80. * Function:        dlst_init
  81. * Returns:      Pointer to a newly created list.
  82. *
  83. * Description:    Initialises a list and returns a pointer to it.
  84. *
  85. ****************************************************************************/
  86. {
  87.     DLIST    *l;
  88.  
  89.     if ((l = (DLIST*)malloc(sizeof(DLIST))) != NULL) {
  90.         l->count = 0;
  91.         l->head = &(l->hz[0]);
  92.         l->z = &(l->hz[1]);
  93.         l->head->next = l->z->next = l->z;
  94.         l->z->prev = l->head->prev = l->head;
  95.         }
  96.     else {
  97.         fprintf(stderr,"Insufficient memory to allocate list\n");
  98.         raise(SIGABRT);
  99.         return NULL;
  100.         }
  101.  
  102.     return l;
  103. }
  104.  
  105. PUBLIC void dlst_kill(DLIST *l,void (*freeNode)(void *node))
  106. /****************************************************************************
  107. *
  108. * Function:        dlst_kill
  109. * Parameters:    l            - List to kill
  110. *                freeNode    - Pointer to user routine to free a node
  111. *
  112. * Description:    Kills the list l, by deleting all of the elements contained
  113. *                within the list one by one and then deleting the list
  114. *                itself. Note that we call the user supplied routine
  115. *                (*freeNode)() to free each list node. This allows the user
  116. *                program to perform any extra processing needed to kill each
  117. *                node (if each node contains pointers to other items on the
  118. *                heap for example). If no extra processing is required, just
  119. *                pass the address of dlst_freenode(), ie:
  120. *
  121. *                    dlst_kill(myList,dlst_freenode);
  122. *
  123. ****************************************************************************/
  124. {
  125.     DLST_BUCKET    *n,*p;
  126.  
  127.     n = l->head->next;
  128.     while (n != l->z) {            /* Free all nodes in list                */
  129.         p = n;
  130.         n = n->next;
  131.         (*freeNode)(DLST_USERSPACE(p));
  132.         }
  133.     free(l);                    /* Free the list itself                    */
  134. }
  135.  
  136. PUBLIC void dlst_insertafter(DLIST *l,void *node,void *after)
  137. /****************************************************************************
  138. *
  139. * Function:        lst_insertafter
  140. * Parameters:    l        - List to insert node into
  141. *                node    - Pointer to user space of node to insert
  142. *                after    - Pointer to user space of node to insert node after
  143. *
  144. * Description:    Inserts a new node into the list after the node 'after'. To
  145. *                insert a new node at the beginning of the list, user the
  146. *                macro DLST_HEAD in place of 'after'. ie:
  147. *
  148. *                    dlst_insertafter(mylist,node,DLST_HEAD(mylist));
  149. *
  150. ****************************************************************************/
  151. {
  152.     DLST_BUCKET    *n = DLST_HEADER(node),*a = DLST_HEADER(after);
  153.  
  154.     n->next = a->next;
  155.     a->next = n;
  156.     n->prev = a;
  157.     n->next->prev = n;
  158.     l->count++;
  159. }
  160.  
  161. PUBLIC void *dlst_deletenext(DLIST *l,void *node)
  162. /****************************************************************************
  163. *
  164. * Function:        lst_deletenext
  165. * Parameters:    l        - List to delete node from.
  166. *                node    - Node to delete the next node from
  167. * Returns:        Pointer to the deleted node's userspace.
  168. *
  169. * Description:    Removes the node AFTER 'node' from the list l.
  170. *
  171. ****************************************************************************/
  172. {
  173.     DLST_BUCKET    *n = DLST_HEADER(node);
  174.  
  175.     node = DLST_USERSPACE(n->next);
  176.     n->next->next->prev = n;
  177.     n->next = n->next->next;
  178.     l->count--;
  179.     return node;
  180. }
  181.  
  182. PUBLIC void *dlst_first(DLIST *l)
  183. /****************************************************************************
  184. *
  185. * Function:        dlst_first
  186. * Parameters:    l        - List to obtain first node from
  187. * Returns:        Pointer to first node in list, NULL if list is empty.
  188. *
  189. * Description:    Returns a pointer to the user space of the first node in
  190. *                the list. If the list is empty, we return NULL.
  191. *
  192. ****************************************************************************/
  193. {
  194.     DLST_BUCKET    *n;
  195.  
  196.     n = l->head->next;
  197.     return (n == l->z ? NULL : DLST_USERSPACE(n));
  198. }
  199.  
  200. PUBLIC void *dlst_last(DLIST *l)
  201. /****************************************************************************
  202. *
  203. * Function:        dlst_last
  204. * Parameters:    l    - List to obtain last node from
  205. * Returns:        Pointer to last node in list, NULL if list is empty.
  206. *
  207. * Description:    Returns a pointer to the user space of the last node in
  208. *                the list. If the list is empty, we return NULL.
  209. *
  210. ****************************************************************************/
  211. {
  212.     DLST_BUCKET    *n;
  213.  
  214.     n = l->z->prev;
  215.     return (n == l->head ? NULL : DLST_USERSPACE(n));
  216. }
  217.  
  218. PUBLIC void *dlst_next(void *prev)
  219. /****************************************************************************
  220. *
  221. * Function:        dlst_next
  222. * Parameters:    prev    - Previous node in list to obtain next node from
  223. * Returns:        Pointer to the next node in the list, NULL at end of list.
  224. *
  225. * Description:    Returns a pointer to the user space of the next node in the
  226. *                list given a pointer to the user space of the previous node.
  227. *                If we have reached the end of the list, we return NULL. The
  228. *                end of the list is detected when the next pointer of a node
  229. *                points back to itself, as does the dummy last node's next
  230. *                pointer. This enables us to detect the end of the list
  231. *                without needed access to the list data structure itself.
  232. *
  233. *                NOTE:    We do no checking to ensure that 'prev' is NOT a
  234. *                        NULL pointer.
  235. *
  236. ****************************************************************************/
  237. {
  238.     DLST_BUCKET    *n = DLST_HEADER(prev);
  239.  
  240.     n = n->next;
  241.     return (n == n->next ? NULL : DLST_USERSPACE(n));
  242. }
  243.  
  244. PUBLIC void *dlst_prev(void *next)
  245. /****************************************************************************
  246. *
  247. * Function:        dlst_prev
  248. * Parameters:    next    - Next node in list to obtain previous node from
  249. * Returns:        Pointer to the previous node in the list, NULL at start list.
  250. *
  251. * Description:    Returns a pointer to the user space of the prev node in the
  252. *                list given a pointer to the user space of the next node.
  253. *                If we have reached the start of the list, we return NULL. The
  254. *                start of the list is detected when the prev pointer of a node
  255. *                points back to itself, as does the dummy head node's prev
  256. *                pointer. This enables us to detect the start of the list
  257. *                without needed access to the list data structure itself.
  258. *
  259. *                NOTE:    We do no checking to ensure that 'next' is NOT a
  260. *                        NULL pointer.
  261. *
  262. ****************************************************************************/
  263. {
  264.     DLST_BUCKET    *n = DLST_HEADER(next);
  265.  
  266.     n = n->prev;
  267.     return (n == n->prev ? NULL : DLST_USERSPACE(n));
  268. }
  269.  
  270. /* Static globals required by merge()    */
  271.  
  272. static DLST_BUCKET    *z;
  273. static int             (*cmp)(void*,void*);
  274.  
  275. PRIVATE DLST_BUCKET *merge(DLST_BUCKET *a,DLST_BUCKET *b,DLST_BUCKET **end)
  276. /****************************************************************************
  277. *
  278. * Function:        merge
  279. * Parameters:    a,b        - Sublist's to merge
  280. * Returns:        Pointer to the merged sublists.
  281. *
  282. * Description:    Merges two sorted lists of nodes together into a single
  283. *                sorted list.
  284. *
  285. ****************************************************************************/
  286. {
  287.     DLST_BUCKET    *c;
  288.  
  289.     /* Go through the lists, merging them together in sorted order    */
  290.  
  291.     c = z;
  292.     while (a != z && b != z) {
  293.         if ((*cmp)(DLST_USERSPACE(a),DLST_USERSPACE(b)) <= 0) {
  294.             c->next = a; c = a; a = a->next;
  295.             }
  296.         else {
  297.             c->next = b; c = b; b = b->next;
  298.             }
  299.         };
  300.  
  301.     /* If one of the lists is not exhausted, then re-attach it to the end
  302.      * of the newly merged list
  303.      */
  304.  
  305.     if (a != z) c->next = a;
  306.     if (b != z) c->next = b;
  307.  
  308.     /* Set *end to point to the end of the newly merged list    */
  309.  
  310.     while (c->next != z) c = c->next;
  311.     *end = c;
  312.  
  313.     /* Determine the start of the merged lists, and reset z to point to
  314.      * itself
  315.      */
  316.  
  317.     c = z->next; z->next = z;
  318.     return c;
  319. }
  320.  
  321. PUBLIC void dlst_mergesort(DLIST *l,int (*cmp_func)(void*,void*))
  322. /****************************************************************************
  323. *
  324. * Function:        dlst_mergesort
  325. * Parameters:    l            - List to merge sort
  326. *                cmp_func    - Function to compare two user spaces
  327. *
  328. * Description:    Mergesort's all the nodes in the list. 'cmp' must point to
  329. *                a comparison function that can compare the user spaces of
  330. *                two different nodes. 'cmp' should work the same as
  331. *                strcmp(), in terms of the values it returns. Rather than
  332. *                waste processing time keeping the previous pointers up to
  333. *                date while performing the mergesort, we simply run through
  334. *                the list at the end of the sort to fix the previous pointers.
  335. *
  336. ****************************************************************************/
  337. {
  338.     int            i,N;
  339.     DLST_BUCKET    *a,*b;        /* Pointers to sublists to merge            */
  340.     DLST_BUCKET    *c;            /* Pointer to end of sorted sublists        */
  341.     DLST_BUCKET    *head;        /* Pointer to dummy head node for list        */
  342.     DLST_BUCKET    *todo;        /* Pointer to sublists yet to be sorted        */
  343.     DLST_BUCKET    *t;            /* Temporary                                */
  344.  
  345.     /* Set up globals required by merge() and pointer to head    */
  346.  
  347.     z = l->z; cmp = cmp_func; head = l->head;
  348.  
  349.     for (N = 1,a = z; a != head->next; N = N + N) {
  350.         todo = head->next; c = head;
  351.         while (todo != z) {
  352.  
  353.             /* Build first sublist to be merged, and splice from main list
  354.              */
  355.  
  356.             a = t = todo;
  357.             for (i = 1; i < N; i++) t = t->next;
  358.             b = t->next; t->next = z; t = b;
  359.  
  360.             /* Build second sublist to be merged and splice from main list
  361.              */
  362.  
  363.             for (i = 1; i < N; i++) t = t->next;
  364.             todo = t->next; t->next = z;
  365.  
  366.             /* Merge the two sublists created, and set 'c' to point to the
  367.              * end of the newly merged sublists.
  368.              */
  369.  
  370.             c->next = merge(a,b,&t); c = t;
  371.             }
  372.         }
  373.  
  374.     /* Fix the previous pointers for the list    */
  375.  
  376.     a = b = l->head;
  377.     b = b->next;
  378.     while (1) {
  379.         b->prev = a;
  380.         if (b == z)
  381.             break;
  382.         a = a->next;
  383.         b = b->next;
  384.         }
  385. }
  386.